/*
 * @Description: request请求
 * @Author: xinqiao lxq1990.0716@qq.com
 * @Date: 2023-03-27
 * @LastEditors: xinqiao lxq1990.0716@qq.com
 * @LastEditTime: 2025-06-12
 */

import { message } from 'ant-design-vue'
import axios, { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'

import { MESSAGE_KEY } from '/@/enums/commonEnum'
import { HttpCodeEnum } from '/@/enums/httpEnum'

type AxiosConfig = AxiosResponse['config']
type ResponseType = Omit<AxiosResponse, 'config'> & {
  config: AxiosConfig
}

const httpConfig = {
  baseURL: import.meta.env.VITE_BASE_API_PATH,
  timeout: 10000,
  withCredentials: true,
  headers: {
    'Content-Type': 'application/json',
  },
}

/** 重新登陆状态码列表 */
const RELOGIN_LIST = [HttpCodeEnum.ERROR_NO_TOKEN, HttpCodeEnum.ERROR_TOKEN_ERROR, HttpCodeEnum.ERROR_TOKEN_INVALID, HttpCodeEnum.ERROR_NO_LOGIN, HttpCodeEnum.ERROR_OTHER_LOGIN]

class RequestHttp {
  instance: AxiosInstance
  requestConfig: IRequestConfig

  public constructor(axiosConfig: AxiosRequestConfig) {
    axiosConfig = { ...axiosConfig, ...{ timeout: 30000 } }
    this.instance = axios.create(axiosConfig)
    this.requestConfig = {
      errTip: true,
    }

    // 请求拦截器
    this.instance.interceptors.request.use(
      (req: AxiosConfig) => {
        return req
      },
      (err: AxiosError) => {
        return Promise.reject(err)
      },
    )

    // 响应拦截器
    this.instance.interceptors.response.use(
      (res: ResponseType) => {
        const { data, config } = res
        if (config?.responseType === 'text') {
          return Promise.resolve({ responseCode: 100000000, responseData: data, headers: res.headers })
        }
        if (config?.responseType === 'blob') {
          return Promise.resolve({ responseCode: 100000000, responseData: data, headers: res.headers })
        }
        const { responseCode, responseMessage } = data
        if (responseCode === HttpCodeEnum.SUCCESS) {
          return Promise.resolve(data)
        } else if (RELOGIN_LIST.includes(responseCode)) {
          return Promise.resolve(data)
        }
        if (!this.requestConfig.errTip) return Promise.resolve(data)
        if (responseMessage) message.error({ content: responseMessage, key: MESSAGE_KEY })
        return Promise.resolve(data)
      },
      (err) => {
        const { config, response } = err
        const { status, data } = response
        const { responseCode, responseMessage, error } = data
        if (RELOGIN_LIST.includes(responseCode)) {
          return Promise.reject(err)
        }
        message.error({ content: responseMessage || error, key: MESSAGE_KEY, duration: 1 })
        const errMsg = data.msg || data.message || '未知错误，请重试'
        if (config.isErr || status === 500 || status === 404) {
          message.destroy()
        }
        err.message = errMsg
        return Promise.reject(err)
      },
    )
  }

  async get<T>(url: string, params: object = {}, config?: IRequestConfig, headers?: Record<string, string>): Promise<T> {
    this.requestConfig = { ...this.requestConfig, ...config }
    return await this.instance.get(url, { params, headers })
  }

  async post<T, D = any>(url: string, data: D, config?: IRequestConfig, headers?: Record<string, string>): Promise<T> {
    this.requestConfig = { ...this.requestConfig, ...config }
    return await this.instance.post(url, data, { headers })
  }

  async downTxt<T>(url: string, params: object = {}, config?: IRequestConfig, headers?: Record<string, string>): Promise<T> {
    this.requestConfig = { ...this.requestConfig, ...config }
    return await this.instance.get(url, { params, responseType: 'text', headers })
  }

  async downFile<T>(url: string, params: object = {}, config?: IRequestConfig, headers?: Record<string, string>): Promise<T> {
    this.requestConfig = { ...this.requestConfig, ...config }
    return await this.instance.get(url, { params, responseType: 'blob', headers })
  }

  async postFile<T, D = any>(url: string, data: D, config: AxiosRequestConfig<D> & { isErr?: boolean } = {}): Promise<T> {
    const { isErr = true, ..._config } = config
    // @ts-ignore
    const res = await this.instance.post(url, data, { ..._config, isErr })
    // 使用类型断言确保返回类型与泛型T匹配
    return res as T
  }
}

export default new RequestHttp(httpConfig)
